﻿using HLStock.MyExcep;
using IdentityModel;
using Microsoft.IdentityModel.Tokens;
using System.Collections;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace HLStock.Common
{
    public class TokenManager
    {
        static SymmetricSecurityKey key;
        static SigningCredentials credentials;
        static JwtSecurityTokenHandler tokenHandler;
        static TokenValidationParameters tokenValidationParameters;
        static readonly string AUDIENCE;
        static readonly string ISSUER;
        static int TTL = 60 * 60 * 24 * 7;
        static TokenManager()
        {
            key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SECRETKEY));
            credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature);
            tokenHandler = new JwtSecurityTokenHandler();
            AUDIENCE = ConfigReader.ReadSetting("JWT", "Audience");
            ISSUER = ConfigReader.ReadSetting("JWT", "Issuer");
            Int32.TryParse(ConfigReader.ReadSetting("JWT", "TTL"), out TTL);
            tokenValidationParameters = new TokenValidationParameters()
            {
                IssuerSigningKey = key,
                ValidAudience = AUDIENCE,
                ValidIssuer = ISSUER,
                ValidateLifetime = true,
            };
        }
        public static TokenValidationParameters GetTokenValidationParameters()
        {
            return tokenValidationParameters;
        }
        public static string MakeToken4User(string userid)
        {
            DateTime dt;
            return MakeToken4User(userid,  out dt);
        }
        public static string MakeToken4User(string userid,  out DateTime expires)
        {
            expires = DateTime.Now.AddMinutes(TTL);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(JwtClaimTypes.Id, userid),
                    new Claim(JwtClaimTypes.Nonce, Guid.NewGuid().ToString().Replace("-","")),
                    new Claim(JwtClaimTypes.Audience, AUDIENCE),
                    new Claim(JwtClaimTypes.Issuer, ISSUER),
                }),
                SigningCredentials = credentials,
                Expires = expires.ToUniversalTime()
            };
            try
            {
                var tokenStr = tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor));
                return tokenStr;
            }
            catch (Exception ex)
            {
                MyLogger.Err(ExceptionUtil.FormatExceptionInfo(ex));
                throw new MyAuthorizationException("创建授权TOKEN失败");
            }
        }
        private static JwtSecurityToken RestoreToken(string tokenStr)
        {
            SecurityToken securityToken;
            try
            {
                var principal = tokenHandler.ValidateToken(tokenStr, tokenValidationParameters, out securityToken);
                JwtSecurityToken jwtSecurityToken = (JwtSecurityToken)securityToken;
                return jwtSecurityToken;
            }
            catch (Exception ex)
            {
                MyLogger.Err(ExceptionUtil.FormatExceptionInfo(ex));
                throw new MyRestoreTokenException("Token验证不正确");
            }
        }
        public static void SetupUser(OnlineUser userInfo)
        {
            var httpContext = ServiceLoader.GetHttpContext();
            var tokenStr = httpContext.Request.Headers["Authorization"].ToString();
            var prefix = "bearer";
            if (tokenStr.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
            {
                tokenStr = tokenStr.Remove(0, prefix.Length).Trim();
            }
            SetupUserFromToken(userInfo, tokenStr);
        }
        public static void SetupUserFromToken(OnlineUser userInfo, string tokenStr)
        {
            var jwtToken = RestoreToken(tokenStr);
            var userid = jwtToken.Payload[JwtClaimTypes.Id].ToString()!;
            userInfo.UserId = userid;
            userInfo.Token = tokenStr;
        }
    }
}
